﻿Option Explicit On

Imports System.Windows.Controls.Canvas

Public MustInherit Class shpPort

#Region "events declaration"
    Public Event Move(ByVal sender As Object, ByVal X As Integer, ByVal Y As Integer)
    Public Event Destruct(ByVal sender As Object)
    Public Event ConnectPort(ByVal sender As Object, ByVal Link As shpPort)
    Public Event DisconnectPort(ByVal sender As Object, ByVal Link As shpPort)
    Public Event PortDoubleClick(ByVal sender As Object, ByVal e As MouseButtonEventArgs)
#End Region

    Protected WithEvents m_Shape As Shape
    Protected WithEvents m_Ancestor As Object
    Protected WithEvents m_Label As clsLabel
    Protected WithEvents m_Tooltip As clsTooltip

    Protected m_Key As String
    Protected m_Type As Byte
    Protected m_Link As shpPort
    Protected m_Connector As shpConnector
    Protected m_Editor As shpEditor
    Protected m_Move As Boolean
    Protected m_Create As Boolean

#Region "properties"
    ' Тип объекта
    Public ReadOnly Property Type() As Integer
        Get
            Return m_Type
        End Get
    End Property
    ' Ключ, с которым порт хранится у родителя
    Public ReadOnly Property Key() As String
        Get
            Return m_Key
        End Get
    End Property
    ' Родитель порта
    Public ReadOnly Property Ancestor() As Object
        Get
            Return m_Ancestor
        End Get
    End Property
    ' Фигура порта (окружность, прямоугольник...)
    Public ReadOnly Property Shape() As Shape
        Get
            Return m_Shape
        End Get
    End Property
    ' Объект надписи порта
    Public ReadOnly Property Label() As clsLabel
        Get
            Return m_Label
        End Get
    End Property
    ' Ссылка на соединенный порт
    Public Property Link() As shpPort
        Get
            Return m_Link
        End Get
        Set(ByVal value As shpPort)
            If value Is Nothing Then
                RaiseEvent DisconnectPort(Me, m_Link)
            Else
                RaiseEvent ConnectPort(Me, value)
            End If
            m_Link = value
        End Set
    End Property
    ' Отсутп слева относительно редактора
    Public ReadOnly Property AbsoluteLeft() As Integer
        Get
            If TryCast(m_Ancestor, shpBlock) IsNot Nothing Then
                Return GetLeft(m_Ancestor) + GetLeft(Me)
            Else
                Return GetLeft(Me)
            End If
        End Get
    End Property
    ' Отсутп сверху относительно редактора
    Public ReadOnly Property AbsoluteTop() As Integer
        Get
            If TryCast(m_Ancestor, shpBlock) IsNot Nothing Then
                Return GetTop(m_Ancestor) + GetTop(Me)
            Else
                Return GetTop(Me)
            End If
        End Get
    End Property
    ' Подключенный соединитель
    Friend Property Connector() As shpConnector
        Get
            Return m_Connector
        End Get
        Set(value As shpConnector)
            m_Connector = value
        End Set
    End Property
    ' Заливка порта
    Public Property Fill() As Brush
        Get
            Return m_Shape.Fill
        End Get
        Set(ByVal value As Brush)
            m_Shape.Fill = value
        End Set
    End Property
#End Region
    ' Перемещение порта
    Public Sub MoveShape(ByVal x As Integer, ByVal y As Integer)
        SetLeft(Me, x)
        SetTop(Me, y)
        If TryCast(m_Ancestor, shpBlock) IsNot Nothing Then
            RaiseEvent Move(Me, GetLeft(m_Ancestor) + x, GetTop(m_Ancestor) + y)
        Else
            RaiseEvent Move(Me, x, y)
        End If
    End Sub
    ' Инициализация порта
    Protected Sub Init(ByVal ancestor As Object, ByVal key As String)
        Dim anc As shpBlock, tip As ToolTip
        m_Ancestor = ancestor
        m_Key = key
        m_Editor = GetEditor(ancestor)
        anc = TryCast(ancestor, shpBlock)
        If anc IsNot Nothing Then
            AddHandler anc.Destruct, AddressOf shpBlock_Destruct
            AddHandler anc.Resize, AddressOf shpBlock_Resize
            AddHandler anc.Move, AddressOf shpBlock_Move
        End If
        Width = c_PortWidth
        Height = c_PortHeight
        m_Label = New clsLabel(Me)
        m_Label.Text = "Comment"
        m_Label.FontSize = 10
        Container.Children.Add(m_Label)
        tip = New ToolTip()
        tip.Content = "Empty ToolTip"
        ToolTip = tip
        m_Tooltip = New clsTooltip(tip)
        Container.Children.Add(m_Tooltip)
        SetZIndex(m_Tooltip, 10)
    End Sub
    ' Удаление порта
    Protected Sub Remove()
        m_Ancestor.Remove(Me)
        RaiseEvent Destruct(Me)
    End Sub

#Region "events"
    Protected Sub itmRemove_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
        Remove()
    End Sub

    Protected Sub itmEdit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
        m_Label.Edit()
    End Sub

    Protected Sub itmTooltip_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
        m_Tooltip.Edit()
    End Sub

    Private Sub shpBlock_GotFocus(ByVal sender As Object, ByVal e As RoutedEventArgs) Handles Me.GotFocus
        m_Shape.Stroke = ColorFocus
        SetZIndex(Me, 3)
    End Sub

    Private Sub shpBlock_LostFocus(ByVal sender As Object, ByVal e As RoutedEventArgs) Handles Me.LostFocus
        m_Label.Edit(False)
        m_Shape.Stroke = ColorStroke
        SetZIndex(Me, 2)
    End Sub

    Protected Sub shpPort_MouseLeftButtonDown(ByVal sender As Object, ByVal e As MouseButtonEventArgs) Handles Me.MouseLeftButtonDown
        m_Editor.FocusObject = Me
    End Sub

    Protected Sub shpPort_MouseEnter(ByVal sender As Object, ByVal e As EventArgs) Handles Me.MouseEnter
        m_Shape.StrokeThickness = c_BorderEnter
        Cursor = Cursors.Arrow
    End Sub

    Protected Sub shpPort_MouseLeave(ByVal sender As Object, ByVal e As EventArgs) Handles Me.MouseLeave
        Dim con As shpConnector, lef As Integer, top As Integer, lef1 As Integer, top1 As Integer
        Dim lef2 As Integer, top2 As Integer, lef3 As Integer, top3 As Integer, shift As Integer
        Dim alef As Integer, atop As Integer, ptyp As Byte
        m_Shape.StrokeThickness = c_BorderLeave
        m_Move = False
        If m_Create Then
            alef = AbsoluteLeft : atop = AbsoluteTop
            ptyp = m_Ancestor.Type
            lef = alef + (c_PortWidth - c_HolderWidth) / 2 : top = atop + (c_PortHeight - c_HolderHeight) / 2
            If m_Type = c_Activator Or m_Type = c_Event Then
                If (m_Type = c_Activator And ptyp = c_Block) Or (m_Type = c_Event And ptyp = c_Editor) Then
                    shift = alef - lef - c_HolderWidth
                Else
                    shift = -alef + lef + c_HolderWidth
                End If
                lef1 = lef + shift : top1 = top
                lef2 = lef1 : top2 = top1 + 1
                lef3 = lef2 + 1 : top3 = top2
            Else
                If (m_Type = c_Input And ptyp = c_Block) Or (m_Type = c_Output And ptyp = c_Editor) Then
                    shift = atop - top - c_HolderHeight
                Else
                    shift = -atop + top + c_HolderHeight
                End If
                lef1 = lef : top1 = top + shift
                lef2 = lef1 + 1 : top2 = top1
                lef3 = lef2 : top3 = top2 + 1
            End If
            con = m_Editor.AddConnector(New Point() {New Point(lef, top), New Point(lef1, top1), New Point(lef2, top2), New Point(lef3, top3)})
            con.SetLeftPort(Me)
            m_Editor.DragObject = con.RightHolder
            m_Create = False
        End If
    End Sub

    Protected Sub shpPort_MouseDoubleClick(ByVal sender As Object, ByVal e As MouseButtonEventArgs) Handles Me.MouseDoubleClick
        Dim typ1 As Type, typ2 As Type
        typ1 = e.OriginalSource.GetType : typ2 = m_Shape.GetType
        If typ1.Equals(typ2) Then
            RaiseEvent PortDoubleClick(Me, e)
        End If
        Dim d As shpBlock
        d = m_Editor.DragObject
    End Sub

    Protected Sub shpShape_MouseLeftButtonDown(ByVal sender As Object, ByVal e As MouseButtonEventArgs) Handles m_Shape.MouseLeftButtonDown
        If m_Connector Is Nothing Then
            m_Create = True
        End If
    End Sub

    Protected Sub shpShape_MouseLeftButtonUp(ByVal sender As Object, ByVal e As MouseButtonEventArgs) Handles m_Shape.MouseLeftButtonUp
        Dim flag As Boolean
        If TryCast(m_Editor.DragObject, clsHolder) IsNot Nothing Then
            If m_Editor.DragObject.IsLast Then
                Dim con As shpConnector
                con = TryCast(m_Editor.DragObject.Ancestor, shpConnector)
                If con IsNot Nothing Then
                    If ((con.LeftPort Is Me) And (con.LeftHolder Is m_Editor.DragObject)) Or ((con.RightPort Is Me) And (con.RightHolder Is m_Editor.DragObject)) Then
                        Exit Sub
                    End If
                    If con.SetPort(m_Editor.DragObject, Me) Then
                        m_Editor.DragObject = Nothing
                        MoveShape(GetLeft(Me), GetTop(Me))
                    Else
                        Dim lin As clsLine, hol As clsHolder
                        Dim lef1 As Double, top1 As Double, lef2 As Double, top2 As Double
                        lin = m_Editor.DragObject.Leftline()
                        If lin Is Nothing Then
                            lin = m_Editor.DragObject.RightLine()
                        End If
                        hol = lin.Neighbor(m_Editor.DragObject)
                        If hol IsNot Nothing Then
                            lef1 = m_Editor.DragObject.nLeft * m_Editor.ZoomX : top1 = m_Editor.DragObject.nTop * m_Editor.ZoomY
                            lef2 = hol.nLeft * m_Editor.ZoomX : top2 = hol.nTop * m_Editor.ZoomY
                            m_Editor.DragObject.MoveShape(ShiftPoint(lef1, lef2, c_PortWidth * 1.5), ShiftPoint(top1, top2, c_PortWidth * 1.5))
                            flag = True
                        End If
                    End If
                End If
            End If
        End If
        If Not flag Then
            Focus()
        End If
        m_Create = False
    End Sub

    Protected Sub shpLabel_MouseLeftButtonDown(ByVal sender As Object, ByVal e As MouseButtonEventArgs) Handles m_Label.MouseLeftButtonDown
        m_Move = True
    End Sub

    Protected Sub shpLabel_MouseLeftButtonUp(ByVal sender As Object, ByVal e As MouseButtonEventArgs) Handles m_Label.MouseLeftButtonUp
        m_Move = False
    End Sub

    Protected Sub shpLabel_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs) Handles m_Label.MouseMove
        Dim x As Integer, y As Integer
        If m_Move Then
            x = e.GetPosition(Me).X - m_Label.ClickX : y = e.GetPosition(Me).Y - m_Label.ClickY
            m_Label.MoveShape(x, y)
        End If
    End Sub
#End Region

#Region "block events"
    Protected Sub shpBlock_Move(ByVal sender As Object, ByVal X As Integer, ByVal Y As Integer)
        RaiseEvent Move(Me, X + GetLeft(Me), Y + GetTop(Me))
    End Sub

    Protected Sub shpBlock_Resize(ByVal sender As Object, ByVal Width As Integer, ByVal Height As Integer)
        RaiseEvent Move(Me, GetLeft(sender) + GetLeft(Me), GetTop(sender) + GetTop(Me))
    End Sub

    Protected Sub shpBlock_Destruct()
        RaiseEvent Destruct(Me)
    End Sub
#End Region
End Class
